﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using RayDen.Library.Data.Xml;

namespace RayDen.Library.Data
{
    public abstract class StorageVault<TKey, TItem> : IEnumerable<TItem>
        where TKey : IComparable<TKey>
    {
        public string Name { get; set; }

        protected Dictionary<TKey, TItem> elements;
        protected abstract TKey GetKey(TItem val);

        public StorageVault()
        {
            this.Name = typeof(TItem).Name + " Storage";
            this.elements = new Dictionary<TKey, TItem>();
        }

        public TItem this[TKey index]
        {
            get { return elements[index]; }
        }

        public void Clear()
        {
            this.elements.Clear();
        }

        public void Delete(TKey key)
        {
            this.elements.Remove(key);
        }
        public void Add(TKey key, TItem v)
        {
            if (!this.elements.ContainsKey(key))
            {
                this.elements.Add(key, v);
            }
        }

        public void Add(TItem value)
        {
            this.elements.Add(GetKey(value), value);
        }

        public void Add(TKey key, TItem v, bool replace)
        {
            if (!this.elements.ContainsKey(key))
            {
                this.elements.Add(key, v);
            }
            else if (replace)
            {
                this.elements[key] = v;
            }
        }

        public void SaveXml(string fileName, Type[] knownTypesArg)
        {
            var knownTypes = knownTypesArg ?? new Type[0];
            var sd = SerializationService.SerializeItems(elements, new[] { typeof(TKey), typeof(TItem), typeof(Dictionary<TKey, TItem>) }.Union(knownTypes).ToArray());
            using (
                var fs = new FileStream(fileName, FileMode.OpenOrCreate,
                                        FileAccess.Write))
            {
                using (var wr = new StreamWriter(fs))
                {
                    wr.Write(sd);
                }
            }
        }

        public virtual void LoadXml(string fileName, Type[] knownTypesArg)
        {
            string fileData;
            var knownTypes = knownTypesArg ?? new Type[0];

            using (
               var fs = new FileStream(fileName, FileMode.Open,
                                       FileAccess.Read))
            {
                using (var wr = new StreamReader(fs))
                {
                    fileData = wr.ReadToEnd();
                }
            }

            var st = (Dictionary<TKey, TItem>)SerializationService.Deserialize(fileData, typeof(Dictionary<TKey, TItem>), new[] { typeof(Dictionary<TKey, TItem>), typeof(TKey), typeof(TItem) }.Union(knownTypes).ToArray());

            this.elements = st;
        }

        public IEnumerator<TItem> GetEnumerator()
        {
            return this.elements.Values.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
}
